package fun.stgoder.test1.source;

public class TestLinkedListSource {

    public static void main(String[] args) {
        SimpleLinkedList<Integer> simpleLinkedList = new SimpleLinkedList<>();
        simpleLinkedList.add(0);
        simpleLinkedList.add(1);
        simpleLinkedList.add(2);
        simpleLinkedList.add(3);
        simpleLinkedList.add(4);

        System.out.println(simpleLinkedList.toString());

        System.out.println("get [2]: " + simpleLinkedList.get(2));

        simpleLinkedList.remove(2);
        System.out.println("remove [2]: " + simpleLinkedList);
        System.out.println("size: " + simpleLinkedList.size());

        simpleLinkedList.remove(0);
        System.out.println("remove [0]: " + simpleLinkedList);
        System.out.println("size: " + simpleLinkedList.size());

        simpleLinkedList.remove(2);
        System.out.println("remove [2]: " + simpleLinkedList);
        System.out.println("size: " + simpleLinkedList.size());

        simpleLinkedList.add(9);
        System.out.println("add 9: " + simpleLinkedList);
        System.out.println("size: " + simpleLinkedList.size());
    }
}

class SimpleLinkedList<E> {
    private Node head;
    private Node tail;
    private int size;

    public void add(E e) {
        if (head == null) {
            head = new Node(e, null);
            tail = head;
        } else {
            tail.next = new Node(e, null);
            tail = tail.next;
        }
        size++;
    }

    public E get(int i) {
        if (i > size - 1)
            throw new ArrayIndexOutOfBoundsException();
        Node<E> node = head;
        for (int j = 0; j < i; j++) {
            if (node == null)
                throw new ArrayIndexOutOfBoundsException();
            node = node.next;
        }
        return node.val;
    }

    public void remove(int i) {
        if (i > size - 1)
            throw new ArrayIndexOutOfBoundsException();
        Node<E> node = head;
        Node<E> pre = null;
        for (int j = 0; j < i; j++) {
            if (node == null)
                throw new ArrayIndexOutOfBoundsException();
            pre = node;
            node = node.next;
        }
        if (node != null) {
            Node<E> next = node.next;
            if (pre == null && next == null) { // only 1 element
                head = null;
                tail = null;
            } else if (pre == null && next != null) { // first element
                head = next;
            } else if (pre != null && next == null) {
                pre.next = null;
                tail = pre;
            } else {
                pre.next = next;
            }
            size--;
        }
    }


    public int size() {
        return size;
    }

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        Node<E> node = head;
        while (node != null) {
            stringBuilder.append(node.val).append(',');
            node = node.next;
        }
        return stringBuilder.toString();
    }

    static class Node<E> {
        private E val;
        private Node next;

        public Node(E val, Node next) {
            this.val = val;
            this.next = next;
        }

        public E val() {
            return val;
        }

        public void val(E val) {
            this.val = val;
        }
    }
}
